﻿using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;
using System.Text;
using BSU.CSCE.Data.Model;
using BSU.CSCE.Data.Repositories.Interfaces;

namespace BSU.CSCE.Data.Repositories
{
    public abstract class BaseRepository<TEntity, IdTEntity> : IRepository<TEntity, IdTEntity>
        where TEntity : class, IEntity<IdTEntity>
    {
        protected BaseRepository()
        {
        }

        protected CSCEDataContext GetNewContext()
        {
            return new CSCEDataContext();
        }

        protected CSCEDataContext GetNewContext(DataLoadOptions dlo, bool useDefaultDataLoadingOptions)
        {
            return new CSCEDataContext(dlo, useDefaultDataLoadingOptions);
        }

        public virtual TEntity Get(IdTEntity id)
        {
            return Get(id, null);
        }

        public virtual TEntity Get(IdTEntity id, CSCEDataContext context)
        {
            return Get<TEntity, IdTEntity>(id, context);
        }

        protected T Get<T, IdT>(IdT id) where T : class, IEntity<IdT>
        {
            return Get<T, IdT>(id, null);
        }

        protected T Get<T, IdT>(IdT id, CSCEDataContext context) where T : class, IEntity<IdT>
        {
            context = context ?? GetNewContext();
            return context.GetTable<T>().SingleOrDefault(e => e.Id.Equals(id));
        }

        public virtual TEntity Save(TEntity entity)
        {
            return Save(entity, null);
        }

        public virtual TEntity Save(TEntity entity, CSCEDataContext context)
        {
            return Save<TEntity, IdTEntity>(entity, context);
        }

        protected T Save<T, IdT>(T entity) where T : class, IEntity<IdT>
        {
            return Save<T, IdT>(entity, null);
        }

        protected T Save<T, IdT>(T entity, CSCEDataContext context) where T : class, IEntity<IdT>
        {
            if (context == null) context = GetNewContext();
            Table<T> table = context.GetTable<T>();
            table.InsertOnSubmit(entity);
            context.SubmitChanges();
            return entity;
        }

        public virtual TEntity Update(TEntity entity)
        {
            return Update(entity, null);
        }

        public virtual TEntity Update(TEntity entity, CSCEDataContext context)
        {
            return Update<TEntity, IdTEntity>(entity, context);
        }

        protected T Update<T, IdT>(T entity) where T : class, IEntity<IdT>
        {
            return Update<T, IdT>(entity, null);
        }

        protected T Update<T, IdT>(T entity, CSCEDataContext context) where T : class, IEntity<IdT>
        {
            if (context == null) context = GetNewContext();
            Table<T> table = context.GetTable<T>();
            table.Attach(entity, true);
            context.SubmitChanges();
            return entity;
        }

        public virtual void Delete(IdTEntity id)
        {
            Delete(id, null);
        }

        public virtual void Delete(IdTEntity id, CSCEDataContext context)
        {
            Delete<TEntity, IdTEntity>(id, context);
        }

        protected void Delete<T, IdT>(IdT id) where T : class, IEntity<IdT>
        {
            Delete<T, IdT>(id, null);
        }

        protected virtual void Delete<T, IdT>(IdT id, CSCEDataContext context) where T : class, IEntity<IdT>
        {
            if (context == null) context = GetNewContext();
            T entity = Get<T, IdT>(id);
            if (entity == null) return;
            Delete<T, IdT>(entity, context);
        }

        public virtual void Delete(TEntity entity)
        {
            Delete(entity, null);
        }

        public virtual void Delete(TEntity entity, CSCEDataContext context)
        {
            Delete<TEntity, IdTEntity>(entity, context);
        }

        protected void Delete<T, IdT>(T entity) where T : class, IEntity<IdT>
        {
            Delete<T, IdT>(entity, null);
        }

        protected void Delete<T, IdT>(T entity, CSCEDataContext context) where T : class, IEntity<IdT>
        {
            if (context == null) context = GetNewContext();
            Table<T> table = context.GetTable<T>();
            table.Attach(entity);
            table.DeleteOnSubmit(entity);
            context.SubmitChanges();
        }

        public virtual List<TEntity> List()
        {
            return List<TEntity>();
        }

        protected List<T> List<T>() where T : class
        {
            CSCEDataContext context = GetNewContext();
            return context.GetTable<T>().ToList();
        }
    }
}
